home *** CD-ROM | disk | FTP | other *** search
- /* CROND & CRONTAB: (c) Kees Lemmens, Netherlands; June 1993.
-
- Programs for ATARI ST (running under MINT) to make it possible
- to run background jobs at regular intervals.
-
- version 1.1: Okt 1993
-
- - Spawned jobs get uid and gid from user who submitted them.
- - Default directory is changed to users homedir.
- (again on special request by Jeroen Berger !)
-
- Any questions or suggestions about this program can be send to:
- lemmens@dv.twi.tudelft.nl
- */
-
- #include "cron.h"
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <time.h>
- #include <process.h>
- #include <signal.h>
- #include <pwd.h>
- #include <sys\wait.h>
-
- extern void LogMsg(char *name, int pid, char *fmt,...);
- extern char *ux2dos(char *);
-
- char *environ[] = { "", NULL };
- /* Environment is not read by Mintshel so it's in fact useless ! */
-
- int sspawnve(int mode,char *cmd, char *argstring, char **envp)
- { char TosArgs[128] = "x";
- int imode;
-
- #ifdef DEBUG
- mode = P_WAIT;
- #endif
-
- ux2dos(cmd);
- ux2dos(argstring);
-
- strncat(TosArgs,argstring,sizeof(TosArgs) - 1);
- *TosArgs = strlen(argstring); /* first byte is strlen */
-
- switch(mode)
- { case P_WAIT : imode= 0; break;
- case P_NOWAIT : imode=100; break;
- case P_OVERLAY : imode=200; break;
- }
-
- return (int)Pexec(imode, cmd, TosArgs, (void *)envp);
- }
-
- void WriteMailHeader(entry *job,FILE *fp)
- { time_t t;
-
- time(&t);
-
- /* first line conform mail headers under UNIX */
-
- fprintf(fp,"From cron %s",ctime(&t));
- fprintf(fp,"To: %s\n",job->User);
- fprintf(fp,"Subject: Output from %s job\n\n",
- job->Type == CRON ? "cron" : "at");
- fprintf(fp,"Command: %s\n\n",job->Command);
-
- fflush(fp);
- }
-
- int StartJob(entry *job,active *ajob)
- { char cmdstring[MAX_TEMPSTR];
- static counter = 0; /* for unique filenames */
- struct passwd *pwent;
- FILE *fp;
- int fd;
-
- /* Use a unique filename for output. Tmpnam can't be used, as it
- also generates $ signs that can confuse the shell !!
- */
-
- #ifdef DEBUG
- strcpy(ajob->Output,"u:/dev/tty");
- #else
- sprintf(ajob->Output,SPOOLDIR "/%08.8d.crn",counter++);
- #endif
-
- strcpy(ajob->User,job->User);
- sprintf(cmdstring,"-c %s; %.*s",DEFPATH,MAX_COMMAND,job->Command);
-
- if ((fp = fopen(ux2dos(ajob->Output),"w")) == NULL)
- return EROUTP;
-
- WriteMailHeader(job,fp);
-
- /* redirect stdout and stderr */
-
- fd=fileno(fp);
- Fforce(1,fd); Fforce(2,fd);
-
- { if((ajob->Pid =(int)fork()) == 0)
- {
- /* must change uid & gid in a subprocess or it will
- be impossible to change back to uid 0 again !
- */
-
- if((pwent = getpwnam(job->User)) != NULL)
- { (void)setuid(pwent->pw_uid);
- (void)setgid(pwent->pw_gid);
-
- Dsetpath(ux2dos(pwent->pw_dir));
- /* this assumes we're in drive u: */
- }
-
- sspawnve(P_OVERLAY,SHELLCMD,cmdstring,environ);
-
- exit(1); /* just in case Pexec overlay fails */
- }
- }
-
- if(ajob->Pid < 0)
- { Fforce(1,0); Fforce(2,0);
- fclose(fp);
- return ERJOB;
- }
- ajob->Status = BUSY;
-
- Fforce(1,0); Fforce(2,0);
- fclose(fp);
- return ajob->Pid;
- }
-
- void HandleExits(active ajobs[])
- { int nr;
- FILE *fp;
- char cmdstring[MAX_COMMAND];
- union
- { long l;
- struct { int Pid; int ExitCode; } c;
- } stat;
-
- /* collect all finished jobs */
-
- while((stat.l=Pwait3(WNOHANG,NULL)) > 0L)
- {
- for(nr=0;nr<MAX_SIMJOBS;nr++)
- { if(ajobs[nr].Pid == stat.c.Pid && ajobs[nr].Status == BUSY)
- {
- LogMsg(PROGNAME,stat.c.Pid,"Job finished (exit=%d)",
- stat.c.ExitCode);
-
- /* append exitcode to mail message */
-
- if ((fp = fopen(ux2dos(ajobs[nr].Output),"a")) != NULL)
- { fprintf(fp,"\nExit code : %d\n",stat.c.ExitCode);
- fclose(fp);
- }
- else
- LogMsg(PROGNAME,stat.c.Pid,"Can't append to output %s",
- ajobs[nr].Output);
-
- ajobs[nr].Status = FINISHED;
- }
- }
- }
-
- /* send output from finished jobs as mail to the user */
-
- #ifndef DEBUG
-
- for(nr=0;nr<MAX_SIMJOBS;nr++)
- {
- if(ajobs[nr].Status != FINISHED)
- continue;
-
- sprintf(cmdstring,"-c " MAILCMD " " MAILARG,
- ajobs[nr].Output,ajobs[nr].User);
-
- sspawnve(P_WAIT,SHELLCMD,cmdstring,environ);
-
- /* and AFTER that (!!) remove the outputfile */
-
- if(remove(ajobs[nr].Output) != 0)
- LogMsg(PROGNAME,stat.c.Pid,"Can't remove output %s",
- ajobs[nr].Output);
-
- ajobs[nr].Status = FREE; /* clear status */
- }
- #endif
- }
-
- void RemoveAtJob(entry *job)
- { char atfile[MAX_FNAME];
-
- sprintf(atfile,"%s/%s.%03d",ATDIR,job->User,job->AtId);
- if(remove(ux2dos(atfile)) < 0)
- LogMsg(PROGNAME, getpid(), "Can't remove %s",atfile);
- }
-
- void DoJobs(entry joblist[], int jobcount, active ajoblist[])
- { int x,n,chpid,cmd;
- int cronout;
- char *message;
-
- for(x=0;x<jobcount;x++)
- {
- if(joblist[x].Status == START)
- {
- for(n=0;n<MAX_SIMJOBS && ajoblist[n].Status != FREE;n++);
-
- /* If no more jobs then don't clear job Status so we'll
- retry next run.
- */
-
- if(n>=MAX_SIMJOBS)
- { LogMsg(PROGNAME,getpid(),"No more active jobs \"%.10s\" (%s)",
- joblist[n].Command,joblist[n].User);
- return;
- }
-
- chpid = StartJob(&joblist[x],&ajoblist[n]);
-
- switch(chpid)
- { case EROUTP:
- message="%Job \".15s\" (%s) no output";
- break;
- case ERJOB:
- message="%Job \".15s\" (%s) failed";
- break;
- default:
- joblist[x].Status = SLEEP;
- switch(joblist[x].Type)
- { case CRON :
- message="CRON job \"%.10s\" (%s) started";
- break;
- case AT :
- message="AT job \"%.10s\" (%s) started";
-
- /* job can be removed: only one run */
- if((cronout=open(CRONPIPE,O_WRONLY)) < 0)
- LogMsg(PROGNAME,getpid(),
- "Internal write to pipe failed");
- else
- { cmd = INTERNBUILD;
- write(cronout,&cmd,1);
- close(cronout);
- }
- RemoveAtJob(&joblist[x]);
- break;
- }
- break;
- }
- LogMsg(PROGNAME,chpid,message,joblist[x].Command,
- joblist[x].User);
-
- #ifdef DEBUG
- DebugPrintTimes(&joblist[x]);
- #endif
-
- }
- }
- }